package com.piggy.msg.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.piggy.common.core.constant.SecurityConstants;
import com.piggy.common.core.enums.UserStatus;
import com.piggy.common.core.exception.base.BaseException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.PagePlus;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.websocket.distribute.MessageDO;
import com.piggy.common.websocket.distribute.RedisMessageDistributor;
import com.piggy.msg.domain.SysStationMessage;
import com.piggy.msg.domain.SysStationMessagePublish;
import com.piggy.msg.domain.bo.SysPublishMsgBo;
import com.piggy.msg.domain.bo.SysStationMessagePublishAddBo;
import com.piggy.msg.domain.bo.SysStationMessagePublishEditBo;
import com.piggy.msg.domain.bo.SysStationMessagePublishQueryBo;
import com.piggy.msg.domain.vo.ReceiverInfoVo;
import com.piggy.msg.domain.vo.SysStationMessagePublishVo;
import com.piggy.msg.server.enums.MarkEnum;
import com.piggy.msg.server.enums.ReceiverType;
import com.piggy.msg.server.mapper.SysStationMessagePublishMapper;
import com.piggy.msg.server.service.ISysStationMessagePublishService;
import com.piggy.msg.server.service.ISysStationMessageService;
import com.piggy.system.api.RemoteDeptService;
import com.piggy.system.api.RemoteRoleService;
import com.piggy.system.api.RemoteUserService;
import com.piggy.system.api.domain.SysDept;
import com.piggy.system.api.domain.SysRole;
import com.piggy.system.api.domain.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * 站内消息发布Service业务层处理
 *
 * @author piggy
 * @date 2021-12-09
 */
@Service
@RequiredArgsConstructor
public class SysStationMessagePublishServiceImpl extends ServiceImpl<SysStationMessagePublishMapper, SysStationMessagePublish> implements ISysStationMessagePublishService {

    private final ISysStationMessageService sysStationMessageService;
    private final RedisMessageDistributor redisMessageDistributor;

    @Resource
    private RemoteRoleService remoteRoleService;

    @Resource
    private RemoteUserService remoteUserService;

    @Resource
    private RemoteDeptService remoteDeptService;



    @Override
    public SysStationMessagePublishVo queryById(Long id){
        return getVoById(id, SysStationMessagePublishVo.class);
    }

    @Override
    public TableDataInfo<SysStationMessagePublishVo> queryPageList(SysStationMessagePublishQueryBo bo) {
        PagePlus<SysStationMessagePublish, SysStationMessagePublishVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo), SysStationMessagePublishVo.class);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<SysStationMessagePublishVo> queryList(SysStationMessagePublishQueryBo bo) {
        return listVo(buildQueryWrapper(bo), SysStationMessagePublishVo.class);
    }

    private LambdaQueryWrapper<SysStationMessagePublish> buildQueryWrapper(SysStationMessagePublishQueryBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysStationMessagePublish> lqw = Wrappers.lambdaQuery();
        lqw.eq(Objects.nonNull(bo.getId()),SysStationMessagePublish::getId,bo.getId());
        lqw.eq(StrUtil.isNotBlank(bo.getLevel()), SysStationMessagePublish::getLevel, bo.getLevel());
        lqw.eq(bo.getStatus() != null, SysStationMessagePublish::getStatus, bo.getStatus());
        lqw.eq(StrUtil.isNotBlank(bo.getType()), SysStationMessagePublish::getType, bo.getType());
        lqw.eq(StrUtil.isNotBlank(bo.getTitle()), SysStationMessagePublish::getTitle, bo.getTitle());
        lqw.like(StrUtil.isNotBlank(bo.getReceiver()), SysStationMessagePublish::getReceiver, bo.getReceiver());
        lqw.eq(StrUtil.isNotBlank(bo.getDescription()), SysStationMessagePublish::getDescription, bo.getDescription());
        lqw.eq(StrUtil.isNotBlank(bo.getState()), SysStationMessagePublish::getState, bo.getState());
        lqw.in(!CollectionUtil.isEmpty(bo.getMsgType()), SysStationMessagePublish::getMsgType, bo.getMsgType());
        lqw.orderByDesc(SysStationMessagePublish::getCreateTime);
        return lqw;
    }

    @Override
    public Boolean insertByAddBo(SysStationMessagePublishAddBo bo) {
        SysStationMessagePublish add = BeanUtil.toBean(bo, SysStationMessagePublish.class);
        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    public Boolean updateByEditBo(SysStationMessagePublishEditBo bo) {
        SysStationMessagePublish update = BeanUtil.toBean(bo, SysStationMessagePublish.class);
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(SysStationMessagePublish entity){
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publish(Long id) {
        final SysStationMessagePublish messagePublish = Optional.ofNullable(this.baseMapper.selectById(id)).orElseThrow(() -> new BaseException("需要发布的消息不存在"));
        final List<Long> receiver = Optional.of(Arrays.stream(messagePublish.getReceiver().split(",")).mapToLong(Long::parseLong).boxed().collect(toList()))
                .orElseThrow(() ->  new BaseException("接受者不能为空"));
        SysStationMessagePublish record = new SysStationMessagePublish();
        record.setId(id);
        record.setStatus(1);
        this.baseMapper.updateById(record);
        final ReceiverType type = ReceiverType.valueOf(messagePublish.getType());
        // 发送目标
        if (ReceiverType.USER.eq(type)) {
            publish(messagePublish, receiver);
        } else if (ReceiverType.ROLE.eq(type)) {
            //根据角色推送消息
            publishByRoleList(messagePublish, receiver);
        } else if (ReceiverType.SCENE.eq(type)) {
            //根据场景推送消息
            publishBySceneList(messagePublish, receiver);
        } else if (ReceiverType.COMPANY.eq(type)) {
            //根据部门推送消息
            publishByDeptList(messagePublish, receiver);
        }
    }

    @Override
    public List<ReceiverInfoVo> getMessageReceiveList(String receiverType) {
        List<ReceiverInfoVo> result = new ArrayList<>();
        final ReceiverType type = ReceiverType.valueOf(receiverType);
        if (ReceiverType.USER.eq(type)) {
            List<SysUser> userList = remoteUserService.queryUserAll(SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(userList)) {
                result = userList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getUserId());
                    vo.setName(s.getUserName());
                    return vo;
                }).collect(Collectors.toList());
            }
        } else if (ReceiverType.ROLE.eq(type)) {
            List<SysRole> roleList = remoteRoleService.queryRoleAll(SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(roleList)) {
                result = roleList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getRoleId());
                    vo.setName(s.getRoleName());
                    return vo;
                }).collect(Collectors.toList());
            }
        } else if (ReceiverType.SCENE.eq(type)) {
            //TODO
        } else if (ReceiverType.COMPANY.eq(type)) {
            List<SysDept> deptList = remoteDeptService.queryDeptAll(SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(deptList)) {
                result = deptList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getDeptId());
                    vo.setName(s.getDeptName());
                    return vo;
                }).collect(Collectors.toList());
            }
        }
        return result;
    }

    @Override
    public void publishMsg(SysPublishMsgBo sysPublishMsgBo) {
        if(ObjectUtil.isEmpty(sysPublishMsgBo)){
            throw new BaseException("消息不能为空");
        }

        if(CollectionUtil.isEmpty(sysPublishMsgBo.getUserIdList())){
            throw new BaseException("发送的用户列表不能为空");
        }

        SysStationMessagePublish messagePublish = BeanUtil.toBean(sysPublishMsgBo,SysStationMessagePublish.class);
        //websocket推送消息
        publish(messagePublish,sysPublishMsgBo.getUserIdList());
    }


    void publish(SysStationMessagePublish messagePublish, List<Long> userIdList) {
        for (Long userId : userIdList) {
            SysStationMessage message = new SysStationMessage();
            message.setTitle(messagePublish.getTitle());
            message.setMark(MarkEnum.UNREAD.getType());
            message.setContent(messagePublish.getContent());
            message.setDescription(messagePublish.getDescription());
            message.setLevel(messagePublish.getLevel());
            message.setReceiveId(userId);
            message.setCreateTime(new Date());
            message.setMsgType(messagePublish.getMsgType());
            sysStationMessageService.save(message);


            // websocket 发送消息
            MessageDO messageDO = new MessageDO();
            messageDO.setNeedBroadcast(Boolean.FALSE);
            messageDO.setSessionKeys(Collections.singletonList(userId));
            messageDO.setMessageText(JSONUtil.toJsonStr(message));
            redisMessageDistributor.distribute(messageDO);
        }
    }

    /**
     * 根据角色推送消息
     * @param messagePublish
     * @param roleList
     */
    private void publishByRoleList(SysStationMessagePublish messagePublish, List<Long> roleList) {
        //1.根据角色列表获取用户id列表
        List<SysUser> userList = remoteRoleService.getRoleUserByRoleIds(roleList,SecurityConstants.INNER).getData();
        List<Long> userIdList = userList.stream()
                .filter(i-> UserStatus.OK.getCode().equals(i.getStatus()))
                .map(SysUser::getUserId).collect(Collectors.toList());
        //2.websocket推送消息
        publish(messagePublish, userIdList);
    }

    /**
     * 根据场景推送消息
     * @param messagePublish
     * @param sceneList
     */
    private void publishBySceneList(SysStationMessagePublish messagePublish, List<Long> sceneList) {
        //1.根据场景列表获取用户id列表
        List<SysUser> userList = remoteRoleService.getRoleUserBySceneIds(sceneList,SecurityConstants.INNER).getData();
        List<Long> userIdList = userList.stream()
                .filter(i-> UserStatus.OK.getCode().equals(i.getStatus()))
                .map(SysUser::getUserId).collect(Collectors.toList());

        //2.websocket推送消息
        publish(messagePublish, userIdList);
    }

    /**
     * 根据部门推送消息
     * @param messagePublish
     * @param deptList
     */
    private void publishByDeptList(SysStationMessagePublish messagePublish, List<Long> deptList) {

        List<SysUser> userList = remoteUserService.getUserByDeptIds(deptList,SecurityConstants.INNER).getData();
        List<Long> userIdList = userList.stream()
                .filter(i-> UserStatus.OK.getCode().equals(i.getStatus()))
                .map(SysUser::getUserId).collect(Collectors.toList());
        //2.websocket推送消息
        publish(messagePublish, userIdList);
    }
}
